home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / games / nhak_src.zip / AMIDOS.C < prev    next >
C/C++ Source or Header  |  1993-09-19  |  18KB  |  774 lines

  1. /*    SCCS Id: @(#)amidos.c msdos.c - Amiga version   3.0    89/05/01
  2. /* NetHack may be freely redistributed.  See license for details. */
  3. /* An assortment of imitations of cheap plastic MSDOS functions.
  4.  */
  5.  
  6. #define NEED_VARARGS
  7. #include "hack.h"
  8.  
  9. #undef TRUE
  10. #undef FALSE
  11. #undef COUNT
  12. #undef NULL
  13.  
  14. #include <libraries/dos.h>
  15. #ifdef LATTICE
  16. #include <proto/exec.h>
  17. #include <proto/dos.h>
  18. #endif
  19.  
  20. /* Prototypes for functions defined in amidos.c */
  21. void NDECL (flushout);
  22. int NDECL (getpid);
  23. int FDECL (abs, (int x));
  24. int NDECL (tgetch);
  25. int NDECL (dosh);
  26. long FDECL (freediskspace, (char *path));
  27. long FDECL (filesize, (char *file));
  28. void FDECL (eraseall, (char *path,
  29.               char *files));
  30. char *FDECL (CopyFile, (char *from,
  31.                char *to));
  32. void FDECL (copybones, (int mode));
  33. void NDECL (playwoRAMdisk);
  34. int FDECL (saveDiskPrompt, (int start));
  35. void NDECL (gameDiskPrompt);
  36. void NDECL (read_config_file);
  37. void NDECL (set_lock_and_bones);
  38. void FDECL (append_slash, (char *name));
  39. void FDECL (getreturn, (char *str));
  40. void VDECL (msmsg, (char *fmt, ...));
  41. FILE * FDECL (fopenp, (char *name,
  42.                       char *mode));
  43. int FDECL (chdir, (char *dir));
  44. void FDECL (msexit, (int code));
  45. static boolean NDECL (record_exists);
  46. static int FDECL (strcmpi, (register char *a, register char *b));
  47.  
  48. extern char Initialized;
  49.  
  50. #ifdef AZTEC_C
  51. struct DateStamp *FDECL(DateStamp, (struct DateStamp *));
  52. BPTR FDECL(Lock, (char *, long));
  53. BPTR FDECL(CurrentDir, (BPTR));
  54. BPTR FDECL(Open, (char *, long));
  55. long FDECL(Read, (BPTR, char *, long));
  56. long FDECL(Write, (BPTR, char *, long));
  57. long NDECL(IoErr);
  58. long FDECL(AvailMem, (long));
  59. void *FDECL(malloc, (unsigned int));
  60. char *FDECL(rindex, (char *, int));
  61. char *FDECL(index, (char *, int));
  62. #endif
  63.  
  64. int Enable_Abort = 0;    /* for stdio package */
  65.  
  66. /* Initial path, so we can find NetHack.cnf */
  67.  
  68. char PATH[PATHLEN] = "Ram:;df0:;NetHack:";
  69.  
  70. void
  71. flushout()
  72. {
  73.     (void) fflush(stdout);
  74. }
  75.  
  76. #ifndef getuid
  77. getuid()
  78. {
  79.     return 1;
  80. }
  81. #endif
  82.  
  83. /*
  84.  *  Actually make up a process id.
  85.  *  Makes sure one can mess less with saved levels...
  86.  */
  87.  
  88. int getpid()
  89. {
  90.     static short pid;
  91.  
  92.     while (pid == 0) {
  93.     struct DateStamp dateStamp;
  94.     pid = rnd(30000);
  95.     pid += (short) DateStamp(&dateStamp);    /* More or less random */
  96.     pid ^= (short) (dateStamp.ds_Days >> 16) ^
  97.            (short) (dateStamp.ds_Days)       ^
  98.            (short) (dateStamp.ds_Minute)     +
  99.            (short) (dateStamp.ds_Tick);
  100.     pid %= 30000;
  101.     }
  102.  
  103.     return (int)pid;
  104. }
  105.  
  106. #ifndef getlogin
  107. char *
  108. getlogin()
  109. {
  110.     return ((char *) NULL);
  111. }
  112. #endif
  113.  
  114. int
  115. abs(x)
  116. int x;
  117. {
  118.     return x < 0? -x: x;
  119. }
  120.  
  121. int
  122. tgetch() {
  123.     char ch;
  124.  
  125.     ch = WindowGetchar();
  126.     return ((ch == '\r') ? '\n' : ch);
  127. }
  128.  
  129. #ifdef DGK
  130. # include <ctype.h>
  131. /* # include <fcntl.h> */
  132.  
  133. # define Sprintf (void) sprintf
  134.  
  135. # ifdef SHELL
  136. int
  137. dosh()
  138. {
  139.     pline("No mysterious force prevented you from using multitasking.");
  140.     return 0;
  141. }
  142. # endif /* SHELL */
  143.  
  144. #define ID_DOS1_DISK    'DOS\1'
  145. #define EXTENSION    72
  146.  
  147. /*
  148.  *  This routine uses an approximation of the free bytes on a disk.
  149.  *  How large a file you can actually write depends on the number of
  150.  *  extension blocks you need for it.
  151.  *  In each extenstion block there are maximum 72 pointers to blocks,
  152.  *  so every 73 disk blocks have only 72 available for data.
  153.  *  The (necessary) file header is also good for 72 data block pointers.
  154.  */
  155. long
  156. freediskspace(path)
  157. char *path;
  158. {
  159.     register long freeBytes = 0;
  160.     register struct InfoData *infoData; /* Remember... longword aligned */
  161.     char fileName[32];
  162.  
  163.     /*
  164.      *    Find a valid path on the device of which we want the free space.
  165.      *    If there is a colon in the name, it is an absolute path
  166.      *    and all up to the colon is everything we need.
  167.      *    Remember slashes in a volume name are allowed!
  168.      *    If there is no colon, it is relative to the current directory,
  169.      *    so must be on the current device, so "" is enough...
  170.      */
  171.     {
  172.     register char *colon;
  173.  
  174.     strncpy(fileName, path, sizeof(fileName)-1);
  175.     fileName[31] = 0;
  176.     if (colon = index(fileName, ':'))
  177.         colon[1] = '\0';
  178.     else
  179.         fileName[0] = '\0';
  180.     }
  181.  
  182.     if (infoData = malloc(sizeof(struct InfoData))) {
  183.     BPTR fileLock;
  184.     if (fileLock = Lock(fileName, SHARED_LOCK)) {
  185.         if (Info(fileLock, infoData)) {
  186.         /* We got a kind of DOS volume, since we can Lock it. */
  187.         /* Calculate number of blocks available for new file */
  188.         /* Kludge for the ever-full VOID: (oops RAM:) device */
  189.         if (infoData->id_UnitNumber == -1 &&
  190.             infoData->id_NumBlocks == infoData->id_NumBlocksUsed) {
  191.             freeBytes = AvailMem(0L) - 64 * 1024L;
  192.             /* Just a stupid guess at the */
  193.             /* Ram-Handler overhead per block: */
  194.             freeBytes -= freeBytes/16;
  195.         } else {
  196.             /* Normal kind of DOS file system device/volume */
  197.             freeBytes = infoData->id_NumBlocks -
  198.                 infoData->id_NumBlocksUsed;
  199.             freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1);
  200.             freeBytes *= infoData->id_BytesPerBlock;
  201.         }
  202.         if (freeBytes < 0)
  203.             freeBytes = 0;
  204.         }
  205.         UnLock(fileLock);
  206.     }
  207.     free(infoData);
  208.     }
  209.     return freeBytes;
  210. }
  211.  
  212.  
  213. long
  214. filesize(file)
  215. char *file;
  216. {
  217.     register BPTR fileLock;
  218.     register struct FileInfoBlock *fileInfoBlock;
  219.     register long size = 0;
  220.  
  221.     if (fileInfoBlock = malloc(sizeof(struct FileInfoBlock))) {
  222.     if (fileLock = Lock(file, SHARED_LOCK)) {
  223.         if (Examine(fileLock, fileInfoBlock)) {
  224.         size = fileInfoBlock->fib_Size;
  225.         }
  226.         UnLock(fileLock);
  227.     }
  228.     free(fileInfoBlock);
  229.     }
  230.     return size;
  231. }
  232.  
  233. /*
  234.  *  On the Amiga, looking if a specific file exists is much faster
  235.  *  than sequentially reading a directory.
  236.  */
  237.  
  238. void
  239. eraseall(path, files)
  240. char *path, *files;
  241. {
  242.     char buf[FILENAME];
  243.     short i;
  244.     BPTR fileLock, dirLock;
  245.  
  246.     if (dirLock = Lock(path ,SHARED_LOCK)) {
  247.     dirLock = CurrentDir(dirLock);
  248.  
  249.     strcpy(buf, files);
  250.     for (i = 0; i <= MAXLEVEL; i++) {
  251.         name_file(buf, i);
  252.         if (fileLock = Lock(buf, SHARED_LOCK)) {
  253.         UnLock(fileLock);
  254.         DeleteFile(buf);
  255.         } else if (IoErr() == ERROR_DEVICE_NOT_MOUNTED)
  256.         break;
  257.         }
  258.  
  259.     UnLock(CurrentDir(dirLock));
  260.     }
  261. }
  262.  
  263. /* This size makes that most files can be copied with two Read()/Write()s */
  264.  
  265. #define COPYSIZE    4096
  266.  
  267. char *CopyFile(from, to)
  268. char *from, *to;
  269. {
  270.     register BPTR fromFile, toFile;
  271.     register char *buffer;
  272.     register long size;
  273.     char *error = NULL;
  274.  
  275.     if (buffer = malloc(COPYSIZE)) {
  276.     if (fromFile = Open(from, MODE_OLDFILE)) {
  277.         if (toFile = Open(to, MODE_NEWFILE)) {
  278.         while (size = Read(fromFile, buffer, (long)COPYSIZE)) {
  279.             if (size != Write(toFile, buffer, size)) {
  280.             error = "Write error";
  281.             break;
  282.             }
  283.         }
  284.         Close(toFile);
  285.         } else /* Can't open destination file */
  286.         error = "Cannot open destination";
  287.         Close(fromFile);
  288.     } else /* Cannot open source file. Should not happen. */
  289.         error = "Huh?? Cannot open source??";
  290.     free(buffer);
  291.     return error;
  292.     } else /* Cannot obtain buffer for copying */
  293.     return "No Memory !";
  294. }
  295.  
  296. void
  297. copybones(mode)
  298. int mode;
  299. {
  300.     BPTR fileLock;
  301.     char from[FILENAME], to[FILENAME];
  302.     char *frompath, *topath, *status;
  303.     short i;
  304.     extern int saveprompt;
  305.  
  306.     if (!ramdisk)
  307.     return;
  308.  
  309.     frompath = (mode != TOPERM) ? permbones : levels;
  310.     topath = (mode == TOPERM) ? permbones : levels;
  311.  
  312.     /* Remove any bones files in `to' directory. */
  313.     eraseall(topath, allbones);
  314.  
  315.     /* Copy `from' to `to' */
  316.     strcpy(from, frompath);
  317.     strcat(from, allbones);
  318.     strcpy(to, topath);
  319.     strcat(to, allbones);
  320.  
  321.     for (i = 1; i < MAXLEVEL; i++) {
  322.     name_file(from, i);
  323.     name_file(to, i);
  324.     if (fileLock = Lock(from, SHARED_LOCK)) {
  325.         UnLock(fileLock);
  326.         if (status = CopyFile(from, to))
  327.         goto failed;
  328.     } else if (IoErr() == ERROR_DEVICE_NOT_MOUNTED) {
  329.         status = "disk not present";
  330.         goto failed;
  331.     }
  332.     }
  333.  
  334.     /*
  335.      * The last file got there.  Remove the ramdisk bones files.
  336.      */
  337.     if (mode == TOPERM)
  338.     eraseall(frompath, allbones);
  339.     return;
  340.  
  341.     /* Last file didn't get there. */
  342.  
  343. failed:
  344.     msmsg("Cannot copy `%s' to `%s'\n(%s)\n", from, to, status);
  345.  
  346.     if (mode == TOPERM) {
  347.     msmsg("Bones will be left in `%s'\n",
  348.         *frompath ? frompath : hackdir);
  349.     return;
  350.     } else {
  351.     /* Remove all bones files on the RAMdisk */
  352.     eraseall(levels, allbones);
  353.     playwoRAMdisk();
  354.     }
  355. }
  356.  
  357. void
  358. playwoRAMdisk()
  359. {
  360.     msmsg("Do you wish to play without a RAMdisk (y/n) ? ");
  361.  
  362.     /* Set ramdisk false *before* exit'ing (because msexit calls
  363.      * copybones)
  364.      */
  365.     ramdisk = FALSE;
  366.     if (Getchar() != 'y') {
  367.     settty("Be seeing you ...\n");
  368.     exit(0);
  369.     }
  370.     set_lock_and_bones();
  371.     return;
  372. }
  373.  
  374. int
  375. saveDiskPrompt(start)
  376. {
  377.     extern int saveprompt;
  378.     char buf[BUFSIZ], *bp;
  379.     BPTR fileLock;
  380.  
  381.     if (saveprompt) {
  382.     /* Don't prompt if you can find the save file */
  383.     if (fileLock = Lock(SAVEF, SHARED_LOCK)) {
  384.         UnLock(fileLock);
  385.         return 1;
  386.     }
  387.     remember_topl();
  388.     home();
  389.     cl_end();
  390.     msmsg("If save file is on a SAVE disk, put that disk in now.\n");
  391.     cl_end();
  392.     msmsg("File name (default `%s'%s) ? ", SAVEF,
  393.         start ? "" : ", <Esc> cancels save");
  394.     getlin(buf);
  395.     home();
  396.     cl_end();
  397.     curs(1, 2);
  398.     cl_end();
  399.     if (!start && *buf == '\033')
  400.         return 0;
  401.  
  402.     /* Strip any whitespace. Also, if nothing was entered except
  403.      * whitespace, do not change the value of SAVEF.
  404.      */
  405.     for (bp = buf; *bp; bp++)
  406.         if (!isspace(*bp)) {
  407.         strncpy(SAVEF, bp, PATHLEN);
  408.         break;
  409.         }
  410.     }
  411.     return 1;
  412. }
  413.  
  414. /* Return 1 if the record file was found */
  415. static boolean
  416. record_exists()
  417. {
  418.     FILE *file;
  419.  
  420.     if (file = fopenp(RECORD, "r")) {
  421.     fclose(file);
  422.     return TRUE;
  423.     }
  424.     return FALSE;
  425. }
  426.  
  427. /* Prompt for game disk, then check for record file.
  428.  */
  429. void
  430. gameDiskPrompt()
  431. {
  432.     extern int saveprompt;
  433.  
  434.     if (record_exists())
  435.     return;
  436.  
  437.     if (saveprompt) {
  438.     (void) putchar('\n');
  439.     getreturn("when the GAME disk has been put in");
  440.     }
  441.  
  442.     if (!record_exists()) {
  443.     msmsg("\n\nWARNING: can't find record file `%s'!\n", RECORD);
  444.  
  445.     msmsg("If the GAME disk is not in, put it in now.\n");
  446.     getreturn("to continue");
  447.     }
  448. }
  449.  
  450. /* Read configuration */
  451. void
  452. read_config_file()
  453. {
  454.     char    tmp_ramdisk[PATHLEN], tmp_levels[PATHLEN];
  455.     char    buf[BUFSZ], *bufp;
  456.     FILE    *fp;
  457.     extern  char plname[];
  458.     extern  int saveprompt;
  459.  
  460.     tmp_ramdisk[0] = 0;
  461.     tmp_levels[0] = 0;
  462.     if ((fp = fopenp(configfile, "r")) == NULL) {
  463.     msmsg("Warning: no configuration file!\n");
  464.     getreturn("to continue");
  465.     return;
  466.     }
  467.     while (fgets(buf, BUFSZ, fp)) {
  468.     if (*buf == '#')
  469.         continue;
  470.  
  471.     /* remove trailing whitespace */
  472.  
  473.     bufp = index(buf, '\n');
  474.     while (bufp > buf && isspace(*bufp))
  475.         bufp--;
  476.     if (bufp == buf)
  477.         continue;         /* skip all-blank lines */
  478.     else
  479.         *(bufp + 1) = 0;    /* 0 terminate line */
  480.  
  481.     /* find the '=' */
  482.     if (!(bufp = index(buf, '='))) {
  483.         msmsg("Bad option line: '%s'\n", buf);
  484.         getreturn("to continue");
  485.         continue;
  486.     }
  487.  
  488.     /* skip  whitespace between '=' and value */
  489.     while (isspace(*++bufp))
  490.         ;
  491.  
  492.     /* Go through possible variables */
  493.     if (!strncmp(buf, "HACKDIR", 4)) {
  494.         strncpy(hackdir, bufp, PATHLEN);
  495.  
  496.     } else if (!strncmp(buf, "RAMDISK", 3)) {
  497.         strncpy(tmp_ramdisk, bufp, PATHLEN);
  498.  
  499.     } else if (!strncmp(buf, "LEVELS", 4)) {
  500.         strncpy(tmp_levels, bufp, PATHLEN);
  501.  
  502.     } else if (!strncmp(buf, "OPTIONS", 4)) {
  503.         parseoptions(bufp, (boolean)TRUE);
  504.         if (plname[0])        /* If a name was given */
  505.         plnamesuffix();    /* set the character class */
  506.  
  507.     } else if (!strncmp(buf, "SAVE", 4)) {
  508.         char *ptr;
  509.         if (ptr = index(bufp, ';')) {
  510.         *ptr = '\0';
  511.         if (*(ptr+1) == 'n' || *(ptr+1) == 'N')
  512.             saveprompt = FALSE;
  513.         }
  514.         (void) strncpy(SAVEF, bufp, PATHLEN);
  515.         append_slash(SAVEF);
  516.     } else if (!strncmp(buf, "GRAPHICS", 4)) {
  517.         unsigned int translate[MAXPCHARS+1]; /* for safety */
  518.         int  lth;
  519.  
  520.         if ((lth = sscanf(bufp,
  521.     "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
  522.                 &translate[0], &translate[1], &translate[2],
  523.                 &translate[3], &translate[4], &translate[5],
  524.                 &translate[6], &translate[7], &translate[8],
  525.                 &translate[9], &translate[10], &translate[11],
  526.                 &translate[12], &translate[13], &translate[14],
  527.                 &translate[15], &translate[16], &translate[17],
  528.                 &translate[18], &translate[19], &translate[20],
  529.                 &translate[21], &translate[22], &translate[23],
  530.                 &translate[24], &translate[25], &translate[26],
  531.                 &translate[27], &translate[28], &translate[29],
  532.                 &translate[30], &translate[31], &translate[32],
  533.                 &translate[33], &translate[34])) < 0) {
  534.             msmsg ("Syntax error in GRAPHICS\n");
  535.             getreturn("to continue");
  536.         } /* Yuck! Worked only with low-byte first!!! */
  537.         assign_graphics(translate, lth);
  538.     } else if (!strncmp(buf, "PATH", 4)) {
  539.         strncpy(PATH, bufp, PATHLEN);
  540.  
  541.     } else {
  542.         msmsg("Bad option line: '%s'\n", buf);
  543.         getreturn("to continue");
  544.     }
  545.     }
  546.     fclose(fp);
  547.  
  548.     strcpy(permbones, tmp_levels);
  549.     if (tmp_ramdisk[0]) {
  550.     strcpy(levels, tmp_ramdisk);
  551.     if (strcmpi(permbones, levels))        /* if not identical */
  552.         ramdisk = TRUE;
  553.     } else
  554.     strcpy(levels, tmp_levels);
  555.     strcpy(bones, levels);
  556. }
  557.  
  558. /* Set names for bones[] and lock[] */
  559.  
  560. void
  561. set_lock_and_bones()
  562. {
  563.     if (!ramdisk) {
  564.     strcpy(levels, permbones);
  565.     strcpy(bones, permbones);
  566.     }
  567.     append_slash(permbones);
  568.     append_slash(levels);
  569.     append_slash(bones);
  570.     strcat(bones, allbones);
  571.     strcpy(lock, levels);
  572.     strcat(lock, alllevels);
  573. }
  574.  
  575. /*
  576.  * Add a slash to any name not ending in / or :.  There must
  577.  * be room for the /.
  578.  */
  579. void
  580. append_slash(name)
  581. char *name;
  582. {
  583.     char *ptr;
  584.  
  585.     if (!*name)
  586.     return;
  587.     ptr = name + (strlen(name) - 1);
  588.     if (*ptr != '/' && *ptr != ':') {
  589.     *++ptr = '/';
  590.     *++ptr = '\0';
  591.     }
  592. }
  593.  
  594.  
  595. void
  596. getreturn(str)
  597. char *str;
  598. {
  599.     int ch;
  600.  
  601.     msmsg("Hit <RETURN> %s.", str);
  602.     while ((ch = Getchar()) != '\n')
  603.     ;
  604. }
  605.  
  606. void
  607. msmsg VA_DECL(char *, fmt)
  608.     VA_START(fmt);
  609.     VA_INIT(fmt, char *);
  610. #ifdef LATTICE
  611.     {
  612.     extern struct Screen *HackScreen;
  613.     char buf[100];
  614.     vsprintf(buf,fmt,VA_ARGS);
  615.     if(HackScreen){
  616.         WindowFPuts(buf);
  617.         WindowFlush();
  618.     } else {
  619.         fprintf(stdout,buf);
  620.         fflush(stdout);
  621.     }
  622.     }
  623. #else
  624.     vprintf(fmt, VA_ARGS);
  625.     (void) fflush(stdout);
  626. #endif
  627.     VA_END();
  628. }
  629.  
  630. /* Follow the PATH, trying to fopen the file.
  631.  */
  632. #define PATHSEP    ';'
  633. #undef fopen
  634.  
  635. FILE *
  636. fopenp(name, mode)
  637. register char *name, *mode;
  638. {
  639.     char buf[BUFSIZ], *bp, *pp, lastch;
  640.     FILE *fp;
  641.     register BPTR theLock;
  642.  
  643.     /* Try the default directory first.  Then look along PATH.
  644.      */
  645.     strcpy(buf, name);
  646.     if (theLock = Lock(buf, SHARED_LOCK)) {
  647.     UnLock(theLock);
  648.     if (fp = fopen(buf, mode))
  649.         return fp;
  650.     }
  651.     pp = PATH;
  652.     while (pp && *pp) {
  653.     bp = buf;
  654.     while (*pp && *pp != PATHSEP)
  655.         lastch = *bp++ = *pp++;
  656.     if (lastch != ':' && lastch != '/' && bp != buf)
  657.         *bp++ = '/';
  658.     strcpy(bp, name);
  659.     if (theLock = Lock(buf, SHARED_LOCK)) {
  660.         UnLock(theLock);
  661.         if (fp = fopen(buf, mode))
  662.         return fp;
  663.     }
  664.     if (*pp)
  665.         pp++;
  666.     }
  667.     return NULL;
  668. }
  669. #endif /* DGK */
  670.  
  671. #ifdef CHDIR
  672.  
  673. /*
  674.  *  A not general-purpose directory changing routine.
  675.  *  Assumes you want to return to the original directory eventually,
  676.  *  by chdir()ing to orgdir.
  677.  *  Assumes -1 is not a valid lock, since 0 is valid.
  678.  */
  679.  
  680. #define NO_LOCK     ((BPTR) -1)
  681.  
  682. char orgdir[1];
  683. static BPTR OrgDirLock = NO_LOCK;
  684.  
  685. chdir(dir)
  686. char *dir;
  687. {
  688.     if (dir == orgdir) {
  689.     /* We want to go back to where we came from. */
  690.     if (OrgDirLock != NO_LOCK) {
  691.         UnLock(CurrentDir(OrgDirLock));
  692.         OrgDirLock = NO_LOCK;
  693.     }
  694.     } else {
  695.     /*
  696.      * Go to some new place. If still at the original
  697.      * directory, save the FileLock.
  698.      */
  699.     BPTR newDir;
  700.  
  701.     if (newDir = Lock(dir, SHARED_LOCK)) {
  702.         if (OrgDirLock == NO_LOCK) {
  703.         OrgDirLock = CurrentDir(newDir);
  704.         } else {
  705.         UnLock(CurrentDir(newDir));
  706.         }
  707.     } else {
  708.         return -1;    /* Failed */
  709.     }
  710.     }
  711.     /* CurrentDir always succeeds if you have a lock */
  712.     return 0;
  713. }
  714.  
  715. #endif
  716.  
  717. /* Chdir back to original directory
  718.  */
  719. #undef exit
  720. void
  721. msexit(code)
  722. {
  723. #ifdef CHDIR
  724.     extern char orgdir[];
  725. #endif
  726.  
  727. #ifdef DGK
  728.     (void) fflush(stdout);
  729.     if (ramdisk)
  730.     copybones(TOPERM);
  731. #endif
  732. #ifdef CHDIR
  733.     chdir(orgdir);      /* chdir, not chdirx */
  734. #endif
  735.  
  736.     CleanUp();
  737.     exit(code);
  738. }
  739.  
  740. /*
  741.  *  Strcmp while ignoring case. Not general-purpose, so static.
  742.  */
  743.  
  744. static int strcmpi(a, b)
  745. register char *a, *b;
  746. {
  747.     while (tolower(*a) == tolower(*b)) {
  748.     if (!*a)        /* *a == *b, so at end of both strings */
  749.         return 0;    /* equal. */
  750.     a++;
  751.     b++;
  752.     }
  753.     return 1;
  754. }
  755.  
  756. /*
  757.  *  memcmp - used to compare two struct symbols, in lev.c
  758.  */
  759.  
  760. #if defined(AZTEC_C) && !defined(memcmp)
  761. memcmp(a, b, size)
  762. register unsigned char *a, *b;
  763. register int size;
  764. {
  765.     while (size--) {
  766.     if (*a++ != *b++)
  767.         return 1;    /* not equal */
  768.     }
  769.  
  770.     return 0;        /* equal */
  771. }
  772. #endif
  773.  
  774.